/*
 * PromptingCommand.java
 *
 * Created on October 3, 2007, 8:53 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package drb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;

/**
 *
 * @author Asger
 */
public abstract class PromptingCommand extends Command {
    
    protected BufferedReader input;
    
    public static final int YES = 1;
    public static final int NO = 2;
    public static final int ANYTHING = 3;
    
    /** Creates a new instance of PromptingCommand */
    public PromptingCommand(BufferedReader input) {
        this.input = input;
    }
    
    protected String getInput()
    {
        try {
            String s = input.readLine();
            if (s.equals("cancel"))
                throw new CancelCommandException();
            if (s.equals("exit"))
                throw new ExitProgramException();
            return s;
        }
        catch (IOException e) {
            throw new RuntimeException("Could not read from console.");
        }
    }
    
    
    protected boolean promptYesNo(String prompt, boolean defaultAnswer)
    {
        System.out.print(prompt);
        if (defaultAnswer)
            System.out.println(" (Y/n)");
        else
            System.out.println(" (y/N)");
        
        while (true)
        {
            String in = getInput();
            if (in.length() == 0)
                return defaultAnswer;
            
            if (in.equalsIgnoreCase("y") || in.equalsIgnoreCase("ye") || in.equalsIgnoreCase("yes"))
                return true;
            
            if (in.equalsIgnoreCase("n") || in.equalsIgnoreCase("no"))
                return false;
            
            System.err.println("Please answer Y (for yes), N (for no), or blank for " + (defaultAnswer? "Yes":"No"));
        }
    }
    
    protected String promptStation(String prompt, Connection connection, boolean allowBlank) throws SQLException
    {
        System.out.println(prompt);
        String station = "";
        
        while (station.length() == 0)
        {
            station = getInput();
            
            if (station.length() == 0 && allowBlank)
                return "";
            
            // Verify that the station exists
            String sql = "SELECT * FROM stations WHERE station_name='"+escapeSQL(station)+"'";
            
            ResultSet result = connection.createStatement().executeQuery(sql);
            
            if (!result.next())
            {
                System.err.println("No station named \"" + station + "\" exists. Please choose another station.");
                station = ""; // Keep asking until we get a real station.
            }
        }
        
        return station;
    }

    protected long promptDateTime(String prompt, long defaultTime) {
        System.out.println(prompt + " (Default is "+formattedDateTime(defaultTime)+")");
        long time = 0;
        
        while (time == 0)
        {
            String dateString = "";
            try
            {
                dateString = getInput();
                if (dateString.length() == 0)
                    time = defaultTime;
                else
                    time = parseDate(dateString);
            } catch (ParseException e) {
                System.err.println("I don't recognize this date: " + dateString);
                System.err.println("The format is like: " + formattedDateTime(defaultTime) + ", which is also the default.");
            }
        }
        
        return time;
    }
    
    protected long promptTime(String prompt) {
        System.out.println(prompt + " (Format is HH:MM)");
        
        while (true) {
            String dateString = "";
            try {
                dateString = getInput();
                return parseTime(dateString);
            } catch (ParseException e) {
                System.err.println("I don't recognize this time: " + dateString);
                System.err.println("The format is: HH:MM, for example: " + formattedTime(getTimeNow()));
            }
        }
    }
    
    protected long parseLongFromCpr(String cpr) throws NumberFormatException
    {
        StringBuffer buffer = new StringBuffer();
        for (int i=0; i<cpr.length(); i++)
            if (cpr.charAt(i) != '-')
                buffer.append(cpr.charAt(i));
        return Long.parseLong( buffer.toString() );
    }
    
    protected Passenger promptPassenger(boolean createIfMissing) throws SQLException {
        assert(connection != null);
        
        System.out.println("Please enter your CPR number:");
        long cprNumber = -1;
        while (cprNumber == -1)
        {
            String cpr = getInput();
            try {
                cprNumber = parseLongFromCpr(cpr);
            } catch (NumberFormatException ex) {
                System.err.println(cpr + " is not a valid CPR number. Please just use numbers (0..9) and the dash (-).");
            }
        }
        
        // See if the passenger already exists
        String sql = "SELECT * FROM passengers WHERE passenger_cpr="+cprNumber;
        ResultSet result = connection.createStatement().executeQuery(sql);
        
        String name = null;
        
        if (result.next())
        {
            name = result.getString("passenger_name");
            return new Passenger(name, cprNumber);
        }
        
        System.out.println("You are a new user. Please enter your name:");
        name = getInput();
        
        if (createIfMissing)
        {
            // Create the passenger in the database
            sql = "INSERT INTO passengers (passenger_cpr, passenger_name) VALUES " +
                    "("+cprNumber+", '"+escapeSQL(name)+"')";
            connection.createStatement().execute(sql);
        }
        
        return new Passenger(name, cprNumber);
    }
    
    protected int promptInt(int min, int max)
    {
        int v = min-1;
        while (v < min || v > max)
        {
            String s = getInput();
            try {
                v = Integer.parseInt(s);
                if (v < min || v > max)
                    System.err.println("Please enter a number between " + min + " and " + max + ".");
            } catch (NumberFormatException ex) {
                System.err.println("Not a valid number. Please enter again: ("+min+"-"+max+")");
            }
        }
        return v;
    }    
    
    protected int promptPositiveInt()
    {
        int v = -1;
        while (v < 1)
        {
            String s = getInput();
            try {
                v = Integer.parseInt(s);
                if (v < 1)
                    System.err.println("Please enter a positive integer.");
            } catch (NumberFormatException ex) {
                System.err.println("Not a valid number. Please enter a positive integer.");
            }
        }
        return v;
    }
    
    protected Ticket promptTicket() throws SQLException {
        System.out.println("Please enter ticket number:");
        Ticket ticket = null;
        while (ticket == null) {
            String s = getInput();
            try {
                int t = Integer.parseInt(s);
                
                String sql = "SELECT * FROM tickets WHERE ticket_id="+t;
                ResultSet result = connection.createStatement().executeQuery(sql);
                if (!result.next())
                {
                    System.err.println("There does not exist a ticket with that number. Please try again.");
                    continue;
                }
                ticket = Ticket.parse(result);
                
            } catch (NumberFormatException ex) {
                System.err.println("Not a valid ticket number. Please try again.");
            }
        }
        return ticket;
    }
    
    protected int promptYesNoAnything(String prompt, int defaultAnswer) {
        System.out.print(prompt);
        if (defaultAnswer == YES)
            System.out.println(" (Y/n/a)");
        else if (defaultAnswer == NO)
            System.out.println(" (y/N/a)");
        else
            System.out.println(" (y/n/A)");
        
        String defaultStr = "Y";
        if (defaultAnswer == NO)
            defaultStr = "N";
        else if (defaultAnswer == ANYTHING)
            defaultStr = "A";
        
        while (true)
        {
            String in = getInput();
            if (in.length() == 0)
                return defaultAnswer;
            
            if (in.equalsIgnoreCase("y") || in.equalsIgnoreCase("ye") || in.equalsIgnoreCase("yes"))
                return YES;
            
            if (in.equalsIgnoreCase("n") || in.equalsIgnoreCase("no"))
                return NO;
            
            if (in.equalsIgnoreCase("a") || in.equalsIgnoreCase("any") || in.equalsIgnoreCase("anything") || in.equalsIgnoreCase("all"))
                return ANYTHING;
            
            System.err.println("Please answer Y (for yes), N (for no), A (for anything, ie. don't care) or blank for " + defaultStr);
        }
    }
    
    public Seat promptSeat(HashSet<Seat> seats) {
        while (true)
        {
            String seatStr = getInput();
            if (seatStr.length() == 0) {        // If nothing was typed in
                return seats.iterator().next(); // Just return any seat.
            }
            else {
                char position = seatStr.charAt(seatStr.length()-1);
                String rowStr = seatStr.substring(0, seatStr.length()-1);
                int row = -1;
                try {
                    row = Integer.parseInt(rowStr);
                } catch (NumberFormatException ex) {}
                
                // See if a seat exists with these row/position
                for (Seat seat : seats) {
                    if (seat.row == row && seat.position == position) {
                        return seat;
                    }
                }
            }
            System.err.println("No seat has that row/position. Please try again, or leave blank to choose any seat.");
        }
    }
    
    public boolean isWagonNumberInSet(int wagonNumber, HashSet<Seat> seats) {
        for (Seat seat : seats) {
            if (seat.wagonNumber == wagonNumber)
                return true;
        }
        return false;
    }
    
    public Seat promptSeatAndWagon(HashSet<Seat> seats) {
        System.out.println("Please type the wagon number you would like a seat from:");
        int wagonNumber = -1;
        while (wagonNumber == -1) {
            wagonNumber = promptPositiveInt();
            if (!isWagonNumberInSet(wagonNumber, seats)) {
                wagonNumber = -1;
                System.err.println("There are no suitable seats in that wagon. Please choose a wagon from the list of selected seats.");
            }
        }
        
        // Filter out seats not in that wagon
        HashSet<Seat> seats2 = new HashSet<Seat>();
        for (Seat seat : seats) {
            if (seat.wagonNumber == wagonNumber)
                seats2.add(seat);
        }
        seats = seats2;
        
        System.out.println("Please type the row and position seat you want: (For example: 3B)");
        return promptSeat(seats);
    }
    
    public String promptWeekDays(String defaultValue) {
        while (true) {
            String s = getInput();
            
            if (s.length() == 0)
                return defaultValue;
            
            if (s.toLowerCase().matches("(mon|tue|wed|thu|fri|sat|sun)(,(mon|tue|wed|thu|fri|sat|sun))*"))
                return s;
            
            System.err.println("Not a valid set of week days. Please try again. Default is: " + defaultValue);
        }
    }
    
    public ScheduleRoute promptScheduleRoute(String stationPrompt, String idPrompt) throws SQLException {
        String startStation = promptStation(stationPrompt, connection, false);
        
        String sql = "SELECT DISTINCT s1.schedule_id FROM schedule s1 WHERE s1.from_name='"+escapeSQL(startStation)+"' AND " +
                "NOT EXISTS (SELECT * FROM schedule s2 WHERE s2.schedule_id=s1.schedule_id AND s2.departure<s1.departure) " +
                "ORDER BY s1.schedule_id";
        ResultSet result = connection.createStatement().executeQuery(sql);
        
        // Get all the routes starting at that station
        ArrayList<ScheduleRoute> routes = new ArrayList<ScheduleRoute>();
        while (result.next())
        {
            int id = result.getInt(1);
            
            sql = "SELECT * FROM schedule WHERE schedule_id="+id+" ORDER BY departure ASC";
            ResultSet r2 = connection.createStatement().executeQuery(sql);
            
            ScheduleRoute route = new ScheduleRoute();
            while (r2.next()) {
                route.schedules.add( TrainSchedule.parse(r2, "") );
            }
            routes.add(route);
        }
        
        // Ask the user to choose which route to copy
        System.out.println("-------------------------------");
        System.out.println("The following routes start at this station:");
        for (ScheduleRoute route : routes) {
            System.out.println("  " + route.getId() + ". " + route);
        }
        System.out.println(idPrompt);
        
        ScheduleRoute route = null;
        while (route == null) {
            int id = promptPositiveInt();
            
            for (ScheduleRoute r : routes) {
                if (r.getId() == id) {
                    route = r;
                    break;
                }
            }
            if (route == null) {
                System.err.println("That route is not on the list. Please choose one of the listed numbers.");
            }
        }
        return route;
    }
}









